// ------------------------------------------------------------------
// Hack.ScreenCapturing.DirectX.Capture
//
// History:
//	2004-Dec-03		dw		- created
//
// Copyright (c) 2004 David Wohlferd
// ------------------------------------------------------------------

using System;
using System.Runtime.InteropServices; 
using Hack.ScreenCapturing.DirectShowLib;

namespace Hack.ScreenCapturing.DirectX.Capture
{
    /// <summary>
    /// </summary>
    public class VideoCompressorCaps : IDisposable
    {
        const int E_NOTIMPLEMENTED = -1; //(int)0x80004001;

        /// <summary>
        /// Video Compression interface for the current device
        /// </summary>
        protected IAMVideoCompression iv = null;
        /// <summary>
        /// compression caps of the current device
        /// </summary>
        protected CompressionCaps cc = 0;

        /// <summary>
        /// Return the capabilities of the current video compressor
        /// </summary>
        public CompressionCaps GetCaps
        {
            get
            {
                return cc;
            }
        }

        /// <summary>
        /// Class constructor
        /// </summary>
        /// <param name="ibf"></param>
        public VideoCompressorCaps(IBaseFilter ibf)
        {
            // Walk all the output pins looking for one that supports
            // IAMVideoCompression.
            IEnumPins ep;
            PinInfo pinInfo;
            IPin[] ppp = new IPin[1];

            int hr = ibf.EnumPins(out ep);
            DsError.ThrowExceptionForHR(hr);

            hr = ep.Next(1, ppp, IntPtr.Zero);
            DsError.ThrowExceptionForHR(hr);

            while (hr == 0)
            {
                hr = ppp[0].QueryPinInfo(out pinInfo);
                DsError.ThrowExceptionForHR(hr);

                if (pinInfo.dir == PinDirection.Output)
                {
                    try
                    {
                        iv = ppp[0] as IAMVideoCompression;

                        if (iv != null)
                        {
                            DsUtils.FreePinInfo(pinInfo);
                            break;
                        }
                    }
                    catch
                    {
                        // Try all the output pins
                    }
                }
                DsUtils.FreePinInfo(pinInfo);
                hr = ep.Next(1, ppp, IntPtr.Zero);
            }

            if ( iv != null )
            {
                // Got an interface.  Does it support any compression opts?
                int l1, l2;
                int r, p;
                double q;
                System.Text.StringBuilder ptr1 = new System.Text.StringBuilder(255, 255);
                System.Text.StringBuilder ptr2 = new System.Text.StringBuilder(255, 255);

                hr = iv.GetInfo( ptr1, out l1, ptr2, out l2, out r, out p, out q, out cc);
                DsError.ThrowExceptionForHR(hr);
            }
        }

        /// <summary>
        /// Read or set the KeyFrameRate.  Non-key frames are diffs from the previous
        /// key frame.  Higher values make editing easier, lower values yield better
        /// compression.
        /// </summary>
        public int KeyFrameRate 
        {
            get
            {
                if ((cc & CompressionCaps.CanKeyFrame) > 0)
                {
                    int k;
                    int hr = iv.get_KeyFrameRate(out k);
                    DsError.ThrowExceptionForHR(hr);

                    return k;
                }

                DsError.ThrowExceptionForHR( E_NOTIMPLEMENTED ); // Not implemented
                return 0;
            }
            set
            {
                if ((cc & CompressionCaps.CanKeyFrame) > 0)
                {
                    int hr = iv.put_KeyFrameRate(value);
                    DsError.ThrowExceptionForHR(hr);
                }
                else
                {
                    DsError.ThrowExceptionForHR( E_NOTIMPLEMENTED ); // Not implemented
                }
            }
        }

        /// <summary>
        /// A compressor defined value of "quality".  100 is best.
        /// </summary>
        public int Quality 
        {
            get
            {
                if ((cc & CompressionCaps.CanQuality) > 0)
                {
                    double k;
                    int i;

                    int hr = iv.get_Quality(out k);
                    DsError.ThrowExceptionForHR(hr);

                    if (k < 429496)
                        i = Convert.ToInt32(k * 100);
                    else
                        i = -1;

                    return i;
                }

                DsError.ThrowExceptionForHR( E_NOTIMPLEMENTED ); // Not implemented

                return 0;
            }
            set
            {
                if ((cc & CompressionCaps.CanQuality) > 0)
                {
                    double d = value;
                    d /= 100;
                    int hr = iv.put_Quality(d);
                    DsError.ThrowExceptionForHR(hr);
                }
                else
                {
                    DsError.ThrowExceptionForHR(E_NOTIMPLEMENTED); // Not implemented
                }
            }
        }

        /// <summary>
        /// The number of frames to look at when trying to achieve a particular
        /// frames per second rate.
        /// </summary>
         public long WindowSize 
        {
            get
            {
                if ((cc & CompressionCaps.CanWindow) > 0)
                {
                    long k;
                    int hr = iv.get_WindowSize(out k);
                    DsError.ThrowExceptionForHR(hr);

                    return k;
                }

                DsError.ThrowExceptionForHR(E_NOTIMPLEMENTED); // Not implemented

                return 0;
            }
            set
            {
                if ((cc & CompressionCaps.CanWindow) > 0)
                {
                    int hr = iv.put_WindowSize(value);
                    DsError.ThrowExceptionForHR(hr);
                }
                else
                {
                    DsError.ThrowExceptionForHR(E_NOTIMPLEMENTED); // Not implemented
                }
            }
        }

        /// <summary>
        /// Applies only to Mpeg compression.
        /// </summary>
         public int PFramesPerKeyFrame
        {
            get
            {
                if ((cc & CompressionCaps.CanBFrame) > 0)
                {
                    int k;
                    int hr = iv.get_PFramesPerKeyFrame(out k);
                    DsError.ThrowExceptionForHR(hr);

                    return k;
                }

                DsError.ThrowExceptionForHR(E_NOTIMPLEMENTED); // Not implemented

                return 0;
            }
            set
            {
                if ((cc & CompressionCaps.CanBFrame) > 0)
                {
                    int hr = iv.put_PFramesPerKeyFrame(value);
                    DsError.ThrowExceptionForHR(hr);
                }
                else
                {
                    DsError.ThrowExceptionForHR(E_NOTIMPLEMENTED); // Not implemented
                }
            }
        }

        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            if ( iv != null )
            { Marshal.ReleaseComObject( iv ); iv = null; }
        }
    }
}
